﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;

using Eflong.Structure;
using Eflong.Utility;

namespace Eflong.SocketClient
{
    public class ClientSocketThread : IDisposable
    {
        public ClientSocketThread( Client client )
        {
            this.client = client;
            m_mutexPacketsIn = new Mutex( );
            m_mutexPacketsOut = new Mutex( );
            m_mutexPacketAct = new Mutex( );

            m_PacketsOut = new List<Packet>( );
            m_PacketsIn = new List<Packet>( );
            list_PacketAct = new List<PacketAck>( );
        }

        public Client client;
        public string m_strServerIPAddress;
        public int m_nPort;

        private uint m_nPacketId; // Id of packet, 0 if broadcasting, big than 0 if requesting;

        private List<Packet> m_PacketsIn;
        private List<Packet> m_PacketsOut;

        private List<PacketAck> list_PacketAct;

        private Mutex m_mutexPacketsIn;
        private Mutex m_mutexPacketsOut;
        private Mutex m_mutexPacketAct;

        ~ClientSocketThread( )
        {
            Dispose( false );
        }

        public void Dispose( )
        {
            Dispose( true );

            GC.SuppressFinalize( this );
        }

        protected virtual void Dispose( bool disposing )
        {
            if ( disposing )
            {
                // 这里是清理"托管资源"的用户代码段
                m_mutexPacketsIn.Close( );
                m_mutexPacketsOut.Close( );
                m_mutexPacketAct.Close( );

                m_PacketsOut.Clear( );
                m_PacketsIn.Clear( );
                list_PacketAct.Clear( );
                m_PacketsOut = m_PacketsIn = null;
                list_PacketAct.Clear( );
                m_mutexPacketAct = null;
                m_mutexPacketsOut = m_mutexPacketAct = null;
            }

            // 这里是清理"非托管资源"的用户代码段
        }

        private uint SendRequest( Packet packet )
        {
            if ( !client.clientSocket.IsConnected( ) ) return m_nPacketId;

            Packet pPacket = new Packet( packet.GetDataSize( ) , packet.GetpData( ) );
            packet.Dispose( );

            pPacket.m_dwId = m_nPacketId;

            AddPacketToSend( pPacket );
            LogWrapper.Logger.Debug( "client.clientThread.SendRequest ..." );
            return m_nPacketId;
        }

        public uint SendRequest( PacketAck packetAck , uint type )
        {
            if ( m_nPacketId == 0x7fffffff ) m_nPacketId = 0;
            m_nPacketId++;

            packetAck.m_dwId = m_nPacketId;

            if ( type != VizClientServer.VCS_MT_UPDATEDATA )
            {
                AddPacketActDeal( packetAck );
            }
            SendRequest( packetAck.packetOut );
            return packetAck.m_dwId;
        }

        public uint SendRequest( PacketAck packetAck , VCS_MT_TYPES type )
        {
            if ( m_nPacketId == 0x7fffffff ) m_nPacketId = 0;
            m_nPacketId++;

            packetAck.m_dwId = m_nPacketId;

            if ( type != VCS_MT_TYPES.VCS_MT_UPDATEDATA )
            {
                AddPacketActDeal( packetAck );
            }
            SendRequest( packetAck.packetOut );
            return packetAck.m_dwId;
        }

        public void AddPacketToSend( Packet pPacket )
        {
            try
            {
                lock ( m_PacketsOut )
                {
                    m_PacketsOut.Add( pPacket );
                }

                ThreadPool.QueueUserWorkItem( new WaitCallback( OnSendPacket ) , null );
                if ( m_PacketsOut.Count > 16 )
                {
                    ClearOrphanPacketsOut( );
                }
            }
            catch ( Exception ex )
            {
                client.DispatchMessage( "AddPacketToSend err : " + ex.Message );
            }
        }

        /// <summary>
        /// 发送请求包
        /// </summary>
        /// <param name="state"></param>
        private void OnSendPacket( object state )
        {
            Packet packet = null;//= (Packet)state;
            do
            {
                packet = TakePacketToSend( 0 );
                if ( packet != null )
                {
                    LogWrapper.Logger.Debug( "client.clientSocket.AsyncSend(packet)" );
                    client.clientSocket.AsyncSend( packet );
                }
            }
            while ( packet != null && packet.m_dwId > 0 );
        }

        private Packet TakePacketToSend( uint dwId )
        {
            Packet pPacket = null;// new Packet(0, null);
            lock ( m_PacketsOut )
            {
                // m_mutexPacketsOut.WaitOne();
                if ( dwId == 0 )
                {
                    if ( m_PacketsOut.Count > 0 )
                    {
                        pPacket = m_PacketsOut[ 0 ];// new Packet(m_PacketsOut[0].GetDataSize(), m_PacketsOut[0].GetpData());
                        m_PacketsOut.RemoveAt( 0 );
                    }
                }
                else
                {
                    for ( int i = 0; i < m_PacketsOut.Count; i++ )
                    {
                        if ( m_PacketsOut[ i ].m_dwId == dwId )
                        {
                            pPacket = m_PacketsOut[ i ];// new Packet(m_PacketsOut[i].GetDataSize(), m_PacketsOut[i].GetpData());
                            m_PacketsOut.RemoveAt( i );
                            break;
                        }
                    }
                }
            }
            return pPacket;
        }

        private void ClearOrphanPacketsOut( )
        {
        }

        private void ClearOrphanPacketsIn( )
        {
        }

        /// <summary>
        /// 加入一个接受的包
        /// </summary>
        /// <param name="packet"></param>
        public void AddPacketReceived( Packet packet )
        {
            if ( !client.IsRunning )
            {
                return;
            }

            if ( packet.m_dwId == 0 )
            {
                client.dispatcher.DispatchPacketReceived( packet );
            }
            else
            {
                lock ( list_PacketAct )
                {
                    bool bFind = false;
                    for ( int n = 0; n < list_PacketAct.Count; n++ )
                    {
                        PacketAck p = list_PacketAct[ n ];
                        if ( p.m_dwId == packet.m_dwId )
                        {
                            bFind = true;
                            p.packetIn = new Packet( packet.GetDataSize( ) , packet.GetpData( ) );
                            p.packetIn.m_dwId = packet.m_dwId;
                            LogWrapper.Logger.Debug( "AddPacketReceived: add packet to list_PacketAct" );

                            client.autoReceived.Set( );
                            break;
                        }
                    }
                    if ( !bFind )
                    {
                        LogWrapper.Logger.Error( "AddPacketReceived:   接收的包未能加入到列表中 list_PacketAct" );
                    }
                }
            }
        }

        /// <summary>
        /// 返回响应包
        /// </summary>
        /// <param name="dwId"></param>
        /// <returns></returns>
        public PacketAck TakePacketActDeal( uint dwId )
        {
            if ( list_PacketAct.Count > 0 )
            {
                PacketAck ack = null;
                lock ( list_PacketAct )
                {
                    for ( int i = 0; i < list_PacketAct.Count; i++ )
                    {
                        ack = list_PacketAct[ i ];
                        if ( ack.m_dwId == dwId )
                        {
                            if ( ack.packetIn != null )
                            {
                                list_PacketAct.RemoveAt( i );
                                break;
                            }
                        }
                    }
                }
                return ack;
            }
            return null;
        }

        public void AddPacketActDeal( PacketAck ack )
        {
            lock ( list_PacketAct )
            {
                list_PacketAct.Add( ack );
                LogWrapper.Logger.Debug( "AddPacketActDeal Add PacketAck" );
            }
        }

        public Packet TakePacketReceived( )
        {
            Packet packet = null;

            lock ( m_PacketsIn )
            {
                if ( m_PacketsIn.Count( ) > 0 )
                {
                    packet = m_PacketsIn[ 0 ];
                    m_PacketsIn.RemoveAt( 0 );
                }
            }

            return packet;
        }
    }
}